<template>
  <div></div>
</template>

<script>
  import * as THREE from 'three'
  import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'
  import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min'

  export default {
    name: 'TwelveTwo',
    data() {
      return {
        cube: null,                     // 立方体对象
        spotLight: null,                // 聚光灯对象
        ambientLight: null,             // 环境光对象
      }
    },
    mounted() {
      this.initScene();
      this.initCamera();
      this.initRenderer();
      this.addCube();
      this.addPlane();
      this.addAxesHelper();
      this.addOrbitControls();
      this.addSpotLight();
      this.addAmbientLight();
      this.animation();
      this.initControl();
      this.listen();
    },
    methods: {
      // 初始化场景
      initScene() {
        this.scene = new THREE.Scene();
      },
      // 初始化相机
      initCamera() {
        // 创建一个相机 视点
        this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        // 设置相机的位置
        this.camera.position.x = -30;
        this.camera.position.y = 40;
        this.camera.position.z = 30;
        this.camera.lookAt(0, 0, 0);
      },
      // 初始化渲染器
      initRenderer() {
        // 创建一个渲染器
        this.renderer = new THREE.WebGLRenderer();
        // 设置渲染器尺寸
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.shadowMap.enabled = true;
        document.body.appendChild(this.renderer.domElement);
      },
      // 添加一个立方体
      addCube() {
        const cubeGeometry = new THREE.BoxGeometry(8, 8, 8);
        const cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff2288 });
        this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        this.cube.position.set(0, 8, 0)
        this.cube.castShadow = true;
        this.scene.add(this.cube);
      },
      // 添加一个平面，用来接收阴影
      addPlane() {
        const planeGeometry = new THREE.PlaneGeometry(100, 100);
        const planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
        const plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.rotation.x = -0.5 * Math.PI;
        plane.position.set(15, 0, 0);
        plane.receiveShadow = true;
        this.scene.add(plane);
      },
      // 添加世界坐标辅助器
      addAxesHelper() {
        const axesHelper = new THREE.AxesHelper(50);
        this.scene.add(axesHelper);
      },
      // 添加轨道控制器
      addOrbitControls() {
        this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
        // 设置带阻尼的惯性
        this.orbitControls.enableDamping = true;
        // 设置阻尼系数
        this.orbitControls.dampingFactor = 0.05;
      },
      // 添加ambientLight光源
      addAmbientLight() {
        this.ambientLight = new THREE.AmbientLight(0xAAAAAA)
        this.scene.add(this.ambientLight)
      },
      // 添加聚光灯光源
      addSpotLight() {
        this.spotLight = new THREE.SpotLight(0xFFFFFF, 50);
        this.spotLight.position.set(-60, 40, -65);
        this.spotLight.decay = 0.5;
        this.spotLight.castShadow = true;
        this.spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
        this.spotLight.shadow.camera.far = 130;
        this.spotLight.shadow.camera.near = 40;
        this.scene.add(this.spotLight);
      },
      // 动画函数
      animation() {
        this.orbitControls.update();
        // 渲染
        this.renderer.render(this.scene, this.camera);
        requestAnimationFrame(this.animation);
      },
      // 初始化lil.gui调试工具
      initControl() {
        const gui = new GUI();

        const ambientLightParams = {
          color: this.ambientLight.color,
          intensity: this.ambientLight.intensity,
        }

        const spotLightParams = {
          visible: this.spotLight.visible,
          color: this.spotLight.color,
          intensity: this.spotLight.intensity,
          distance: this.spotLight.distance,
          angle: this.spotLight.angle,
          penumbra: this.spotLight.penumbra,
          decay: this.spotLight.decay,
        }

        let ambientLightFolder = gui.addFolder('环境光属性');
        ambientLightFolder.addColor(ambientLightParams, 'color').name('color-颜色').onChange(val => {
          this.ambientLight.color = val;
        })
        ambientLightFolder.add(ambientLightParams, 'intensity', 1, 100).step(1).name('intensity-强度').onChange(val => {
          this.ambientLight.intensity = val;
        })

        let spotLightFolder = gui.addFolder('聚光灯属性');
        spotLightFolder.add(spotLightParams, 'visible').name('visible-是否显示').onChange(val => {
          this.spotLight.visible = val;
        })
        spotLightFolder.addColor(spotLightParams, 'color').name('color-颜色').onChange(val => {
          this.spotLight.color = val;
        })
        spotLightFolder.add(spotLightParams, 'intensity', 1, 100).step(1).name('intensity-强度').onChange(val => {
          this.spotLight.intensity = val;
        })
        spotLightFolder.add(spotLightParams, 'distance', 1, 1000).step(1).name('distance-距离').onChange(val => {
          this.spotLight.distance = val;
        })
        spotLightFolder.add(spotLightParams, 'angle', 0, Math.PI / 2).name('angle-角度').onChange(val => {
          this.spotLight.angle = val;
        })
        spotLightFolder.add(spotLightParams, 'penumbra', 0, 1).name('penumbra-边缘衰减度').onChange(val => {
          this.spotLight.penumbra = val;
        })
        spotLightFolder.add(spotLightParams, 'decay', 0, 5).name('decay-光线衰减度').onChange(val => {
          this.spotLight.decay = val;
        })
      },
      listen() {
        // 监听窗口变化
        window.addEventListener('resize', () => {
          // 重置渲染器宽高比
          this.renderer.setSize(window.innerWidth, window.innerHeight);
          // 重置相机宽高比
          this.camera.aspect = window.innerWidth / window.innerHeight;
          // 更新相机投影矩阵
          this.camera.updateProjectionMatrix();
        })
      }
    }
  }
</script>

<style scoped>

</style>
